#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "log.hpp"
#include "Task.hpp"
#include "thread_pool.hpp"

Log lg;

enum
{
    SocketFail = 1,
    BindFail,
    ListenError
};
class tcpServer
{
public:
    tcpServer(std::string ip = "0.0.0.0", uint16_t port = 7778)
        : ip_(ip), port_(port)
    {
    }
    ~tcpServer()
    {
    }

    void init()
    {
        // socket
        sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd_ < 0)
        {
            lg(Fatal, "server create fail");
            exit(SocketFail);
        }
        lg(Debug, "server create success");

        // bind
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        inet_pton(AF_INET, ip_.c_str(), &local.sin_addr);
        local.sin_port = htons(port_);
        int n = bind(sockfd_, (struct sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            lg(Fatal, "server bind fail");
            exit(BindFail);
        }
        lg(Debug, "server bind success");
        // listen
        if (listen(sockfd_, 10) < 0)
        {
            lg(Fatal, "listen error");
            exit(ListenError);
        }
        lg(Debug, "listen success");
    }

    void run()
    {
        //线程池单例模式
        threadPool<Task>::getInstance()->init();
        lg(Debug, "server is running");
        while (1)
        {
            // accept
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int lis_fd = accept(sockfd_, (struct sockaddr *)&client, &len);
            uint16_t port = ntohs(client.sin_port);
            char ipbuf[50];
            string ip = inet_ntop(AF_INET, &client, ipbuf, sizeof(ipbuf));
            Task t(lis_fd, port, ip);
            threadPool<Task>::getInstance()->push(t);
        }
    }

private:
    int sockfd_;
    std::string ip_;
    uint16_t port_;
};